/* 类声明 */
// class Greeter {
//     greeting: string;
//     constructor(message: string) {
//         this.greeting = message;
//     }
//     greet() {
//         console.log("Hello, " + this.greeting);
//     }
// }

// let greeter = new Greeter("world");
// greeter.greet()

/* 继承 */
// class Animal {
//     move(distanceInMeters: number = 0) {
//         console.log(`Animal moved ${distanceInMeters}m.`);
//     }
// }

// class Dog extends Animal {
//     bark() {
//         console.log("Woof! Woof!");
//     }
// }

// const dog = new Dog();
// dog.bark();
// dog.move(10);

/* 继承2 */
// class Animal {
//     name: string;
//     constructor(theName: string) {
//         this.name = theName;
//     }
//     move(distanceInMeters: number = 0) {
//         console.log(`${this.name} moved ${distanceInMeters}m.`);
//     }
// }

// class Snake extends Animal {
//     // constructor(name: string) {
//     //     super(name);
//     // }
//     move(distanceInMeters = 5) {
//         console.log("Slithering...");
//         super.move(distanceInMeters);
//     }
// }

// class Horse extends Animal {
//     // constructor(name: string) {
//     //     super(name);
//     // }
//     move(distanceInMeters = 45) {
//         console.log("Galloping...");
//         super.move(distanceInMeters);
//     }
// }

// let sam = new Snake("Sammy the Python");
// let tom = new Horse("Tommy the Palomino");

// sam.move();
// tom.move(34);

/* 公共，私有与受保护的修饰符 */
/* private */
// class Animal {
//     private name: string;
//     constructor(theName: string) {
//         this.name = theName;
//     }
//     sayHello() {
//         console.log(`${this.name}:hello`);
//     }
// }
// console.log(new Animal("").name);
// new Animal("犀牛").sayHello()

// class Rhino extends Animal {
//     constructor() {
//         super("Rhino");
//     }
//     sayHello() {
//         console.log(`${this.name}:hello`);//编译错误 无法访问Animal定义的私有成员
//     }
// }

// let animal = new Animal("Goat");
// let rhino = new Rhino();

/* protected属性 */
// class Person {
//     // 子类也能访问
//     protected name: string;
//     constructor(name: string) { this.name = name; }
// }

// class Employee extends Person {
//     private department: string;

//     constructor(name: string, department: string) {
//         super(name)
//         this.department = department;
//     }

//     public getElevatorPitch() {
//         // 父类中定义的protected成员 在子类中也可以访问
//         return `Hello, my name is ${this.name} and I work in ${this.department}.`;
//     }
// }

// let howard = new Employee("Howard", "Sales");
// console.log(howard.getElevatorPitch());
// console.log(howard.name); // 错误

/* protected构造函数 */
// class Person {
//     protected name: string;
//     protected constructor(theName: string) { this.name = theName; }
// }

// // Employee 能够继承 Person
// class Employee extends Person {
//     private department: string;

//     constructor(name: string, department: string) {
//         super(name);
//         this.department = department;
//     }

//     public getElevatorPitch() {
//         return `Hello, my name is ${this.name} and I work in ${this.department}.`;
//     }
// }

// let howard = new Employee("Howard", "Sales");
// let john = new Person("John"); // 错误: 'Person' 的构造函数是被保护的.

/* readonly修饰符 */
// class Octopus {
//     readonly name: string;
//     readonly numberOfLegs: number = 8;
//     constructor (theName: string) {
//         this.name = theName;
//     }
// }
// let dad = new Octopus("Man with the 8 strong legs");
// console.log(dad.name);
// dad.name = "Man with the 3-piece suit"; // 错误! name 是只读的.

/* 参数属性 */
// class Animal {
//     constructor(private name: string) {}
//     move(distanceInMeters: number) {
//         console.log(`${this.name} moved ${distanceInMeters}m.`);
//     }
// }
// new Animal("章鱼").move(10)
// console.log(new Animal("章鱼").name);


/* 存取器 */
// let passcode = "secret passcode123";

// class Employee {
//     private _fullName: string;

//     get fullName(): string {
//         return this._fullName;
//     }

//     set fullName(newName: string) {
//         // this._fullName = newName;
//         if (passcode && passcode == "secret passcode") {
//             this._fullName = newName;
//         } 
        
//         else {
//             console.log("Error: Unauthorized update of employee!");
//         }
//     }
// }

// let employee = new Employee();

// // 访问setter
// employee.fullName = "Bob Smith123";

// if (employee.fullName) {
//     // 访问getter
//     console.log(employee.fullName);
// }


/* 静态属性 */
// class Grid {
//     // Grid.origin通过类名访问 this.xxx通过示例访问
//     static origin = {x: 0, y: 0};

//     // 示例方法
//     calculateDistanceFromOrigin(point: {x: number; y: number;}) {
//         let xDist = (point.x - Grid.origin.x);
//         let yDist = (point.y - Grid.origin.y);
//         return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
//     }

//     constructor (public scale: number) { }
// }

// let grid1 = new Grid(1.0);  // 1x scale
// let grid2 = new Grid(5.0);  // 5x scale

// console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
// console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));

/* 抽象类 */
abstract class Department {

    constructor(public name: string) {
    }

    printName(): void {
        console.log('Department name: ' + this.name);
    }

    // 只定义类型不定义具体实现的方法——抽象方法
    // 只要有一个方法是抽象的 则整个类是抽象类
    abstract printMeeting(): void; // 必须在派生类中实现
}

// 继承一个抽象类
class AccountingDepartment extends Department {

    constructor() {
        super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super()
    }

    // 对抽象方法做具体实现
    printMeeting(): void {
        console.log('The Accounting Department meets each Monday at 10am.');
    }

    // 扩展出子类自己的方法
    generateReports(): void {
        console.log('Generating accounting reports...');
    }
}

let department: Department; // 允许创建一个对抽象类型的引用
// department = new Department(); // 错误: 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值

// 父类对象department可以访问定义在Department中的全部属性
department.printName();
department.printMeeting();
// department.generateReports(); // 错误: 方法在声明的抽象类中不存在

// 想访问特定部门（子类）的特定方法 则需要先做类型断言
(department as AccountingDepartment).generateReports();
(<AccountingDepartment>department).generateReports()

/* 把类当做接口使用 */
class Point {
    x: number;
    y: number;
}

interface Point3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};

